package com.cloud.sample.provider;

import com.cloud.common.util.JsonUtils;
import com.cloud.sample.cache.WechatCache;
import com.cloud.sample.config.WechatConfig;
import com.cloud.sample.dto.WechatSignDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

@Slf4j
@Component
@RefreshScope
public class WechatProvider {
    private static final String OAUTH2_URL = "https://api.weixin.qq.com/sns/oauth2";
    private static final String CGI_URL = "https://api.weixin.qq.com/cgi-bin";

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private WechatCache wechatCache;

    @Autowired
    private WechatConfig wechatConfig;

    /**
     * 获取openid
     *
     * @param code
     * @return
     */
    private String getOpenid(String code) {
        String apiUrl = OAUTH2_URL + "/access_token?grant_type=authorization_code&appid=" + wechatConfig.getAppId() + "&secret=" + wechatConfig.getAppSecret() + "&code=" + code;
        String resultText = restTemplate.exchange(apiUrl, HttpMethod.GET, HttpEntity.EMPTY, String.class).getBody();
        Map<String, Object> map = JsonUtils.parseObject(resultText, Map.class);
        return (String) map.get("openid");
    }

    /**
     * 获取签名数据
     *
     * @param url
     * @return String
     */
    public WechatSignDTO getSignature(String url) {
        try {
            String ticket = wechatCache.getTicket(wechatConfig.getAppId());
            if (StringUtils.isEmpty(ticket)) {
                String accessToken = getAccessToken(wechatConfig.getAppId(), wechatConfig.getAppSecret());
                if (StringUtils.isEmpty(accessToken)) {
                    return null;
                }
                ticket = getTicket(accessToken);
                if (StringUtils.isEmpty(ticket)) {
                    return null;
                }
                wechatCache.saveTicket(wechatConfig.getAppId(), ticket);
            }
            WechatSignDTO wechatSignDTO = new WechatSignDTO();
            wechatSignDTO.setAppId(wechatConfig.getAppId());
            wechatSignDTO.setNonceStr(RandomStringUtils.randomAlphanumeric(16));
            wechatSignDTO.setTimestamp(System.currentTimeMillis() / 1000 + "");

            StringBuilder signStr = new StringBuilder();
            signStr.append("jsapi_ticket=").append(ticket);
            signStr.append("&noncestr=").append(wechatSignDTO.getNonceStr());
            signStr.append("&timestamp=").append(wechatSignDTO.getTimestamp());
            signStr.append("&url=").append(url);
            String signature = sha1(signStr.toString());

            wechatSignDTO.setSignature(signature);
            return wechatSignDTO;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    private String sha1(String decript) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance("SHA-1");
        digest.update(decript.getBytes());
        byte byteArray[] = digest.digest();

        StringBuffer hexString = new StringBuffer();
        for (int i = 0; i < byteArray.length; i++) {
            String shaHex = Integer.toHexString(byteArray[i] & 0xFF);
            if (shaHex.length() < 2) {
                hexString.append(0);
            }
            hexString.append(shaHex);
        }
        return hexString.toString();
    }

    private String getAccessToken(String appId, String appSecret) {
        String apiUrl = CGI_URL + "/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
        String resultText = restTemplate.exchange(apiUrl, HttpMethod.GET, HttpEntity.EMPTY, String.class).getBody();
        log.info("getAccessToken >>> {}", resultText);
        Map<String, Object> map = JsonUtils.parseObject(resultText, Map.class);
        return (String) map.get("access_token");
    }

    private String getTicket(String accessToken) {
        String apiUrl = CGI_URL + "/ticket/getticket?type=jsapi&access_token=" + accessToken;
        String resultText = restTemplate.exchange(apiUrl, HttpMethod.GET, HttpEntity.EMPTY, String.class).getBody();
        log.info("getJsapiTicket >>> {}", resultText);
        Map<String, Object> map = JsonUtils.parseObject(resultText, Map.class);
        return (String) map.get("ticket");
    }

}
